import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs'
import Table from '../../ch/demo/Table.vue'
import TableSortable from '../../ch/demo/TableSortable.vue'

<Meta
  title="Components/Table"
  component={Table}
  argTypes={{
    variant: {
      control: {
        type: 'select',
        options: ['default', 'compact']
      }
    }
  }}
/>

export const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { Table },
  template: '<Table :variant="variant" :caption="caption" :displayCaption="displayCaption" :zebra="zebra" />',
});

export const TemplateSortable = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { TableSortable },
  template: '<TableSortable :variant="variant" :caption="caption" :displayCaption="displayCaption" :zebra="zebra"  :id="id" />',
});

# Table

<a href="?path=/story/components-table--example">
  Go to the Canvas Tab
</a>

---

<a href="?id=components-table--example" target="_blank">
  Open page in full width in a new tab
</a>

<Canvas>
  <Story
    name="Example"
    args={{
      variant: 'default',
      caption: 'Short description of the table content for better accessibility',
      displayCaption: true,
      zebra: false,
    }}
  >
    {Template.bind({})
  }</Story>
</Canvas>

<ArgsTable story="Example" />

## Variants

Add `table--compact` to the table element to use the compact variant. This variant is used for tables with a lot of data.
Add `table--zebra` to the table element to use the zebra variant. This variant is rencommended for large and wide tables, to distinguish visually rows.

## Alignment
Text alignment in a table is done cell by cell. Add a `.text-right` or `.text-center` class to the `<td>` or the `<th>` element to align the text correctly. By default, text is aligned to the left. The `align` attribute is another valid way to align content in a table context.


## Accessibility

Add a recommended `<caption>` element right after the `<table>` opening tag for better accessibility. This is used by screen readers to provide a label for the table. It is also used by assistive technologies to help users navigate the table and understand what data is being displayed and how it is organized.

Per default, the `<caption>` element is visually hidden. If you want to display the caption, you can use the `table--caption` modifier class. This will display the caption above the table.

Use `<th>` elements to define headers. They should have a `scope` attribute with a value of `row` or `col`. This is used by screen readers to help users understand the structure of the table data and navigate the table more efficiently.

```html
<table class="table table--default table--caption">
  <caption>
    Short description of the table content for better accessibility
  </caption>
  <thead>
    <tr>
      <th scope="col">Header col one</th>
      <th scope="col">Header col two</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Header for row one</th>
      <td>Row one col two</td>
    </tr>
    <tr>
      <th scope="row">Header for row two</th>
      <td>Row two col two</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <th scope="row">Footer</th>
      <td>
        Footer col two
      </td>
    </tr>
  </tfoot>
</table>
```

# Sortable Table

<a href="?path=/story/components-table--example-sortable">
  Go to the Canvas Tab
</a>

---

<a href="?id=components-table--example-sortable" target="_blank">
  Open page in full width in a new tab
</a>

<Canvas>
  <Story
    name="Example Sortable"
    args={{
      variant: 'default',
      caption: 'Short description of the table content for better accessibility',
      displayCaption: false,
      zebra: true,
      id: '1',
    }}
  >
    {TemplateSortable.bind({})
  }</Story>
</Canvas>

<ArgsTable story="Example Sortable" />

## Markup example

```html
<table
  id="table-sortable-1"
  class="table table--default table--sortable"
>
  <caption>
    Description of the table content here
    <span class="sr-only">, column headers with buttons are sortable.</span>
  </caption>
  <thead>
    <tr>
      <th scope="col" aria-sort="ascending">
        <button class="table__sorter">
          Header col one
          <span aria-hidden="true"></span>
        </button>
      </th>
      <th scope="col">
        <button class="table__sorter">
          Header col two
          <span aria-hidden="true"></span>
        </button>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Col 1 row 1</td>
      <td>Col 2 row 1</td>
    </tr>
    <tr>
      <td>Col 1 row 2</td>
      <td>Col 2 row 2</td>
    </tr>
  </tbody>
</table>
```

## Accessibility

To help screen reader users understand the purpose of the buttons in the column headers, an off-screen description of the sort functionality of the buttons is appended to the `<caption>` element. This description is hidden from sighted users with the `.sr-only` class.

The `aria-sort` attribute is added to the column header that is currently sorted. The value of the attribute is set to `ascending` or `descending` depending on the current sort order. If the column is not sorted, the attribute is removed.

The `aria-hidden` attribute is added to the sort icon in the column header. This is done to prevent screen readers from announcing the icon.


## JavaScript

Below an example of a basic script to make the table sortable. Complexities like sorting multiple page results, dates, etc. are not included in this example, but the script can be used as a starting point for your own implementation.

```javascript
module.exports = class TableSortable {
  constructor(id) {
    this.tableNode = document.getElementById(id)
    this.columnHeaders = Array.from(this.tableNode.querySelectorAll('thead th'))

    this.columnHeaders.forEach((ch, i) => {
      const buttonNode = ch.querySelector('button')
      if (buttonNode) {
        buttonNode.setAttribute('data-column-index', i)
        buttonNode.addEventListener('click', this.handleClick.bind(this))
      }
    })
  }

  setColumnHeaderSort (columnIndex) {
    if (typeof columnIndex === 'string') {
      columnIndex = parseInt(columnIndex)
    }

    this.columnHeaders.forEach((ch, i) => {
      const buttonNode = ch.querySelector('button')
      if (i === columnIndex) {
        const value = ch.getAttribute('aria-sort')
        const sortDirection =
          value === 'descending' || !value ? 'ascending' : 'descending'
        ch.setAttribute('aria-sort', sortDirection)
        this.sortColumn(
          columnIndex,
          sortDirection,
          ch.classList.contains('num') ? 'number' : 'text'
        )
      } else {
        if (ch.hasAttribute('aria-sort') && buttonNode) {
          ch.removeAttribute('aria-sort')
        }
      }
    })
  }
  sortColumn (columnIndex, sortValue, type) {
    const tbodyNode = this.tableNode.querySelector('tbody')
    const rowNodes = Array.from(tbodyNode.children)

    rowNodes.sort((a, b) => {
      const aCell = a.querySelectorAll('th, td')[columnIndex]
      const bCell = b.querySelectorAll('th, td')[columnIndex]

      let aValue = ''
      let bValue = ''

      if (type === 'number') {
        aValue = parseFloat(aCell.textContent.toLowerCase().trim())
        bValue = parseFloat(bCell.textContent.toLowerCase().trim())
      } else if (type === 'date') {
        aValue = aCell.getAttribute('value').toLowerCase().trim()
        bValue = bCell.getAttribute('value').toLowerCase().trim()
      } else {
        aValue = aCell.textContent.toLowerCase().trim()
        bValue = bCell.textContent.toLowerCase().trim()
      }

      if (type === 'number') {
        if (sortValue === 'ascending') {
          return aValue - bValue
        } else {
          return bValue - aValue
        }
      } else {
        if (sortValue === 'ascending') {
          return aValue.localeCompare(bValue)
        } else {
          return bValue.localeCompare(aValue)
        }
      }
    })

    // Remove rows
    while (tbodyNode.firstChild) {
      tbodyNode.removeChild(tbodyNode.firstChild)
    }

    // Add sorted rows
    for (const rowNode of rowNodes) {
      tbodyNode.appendChild(rowNode)
    }
  }

  /* EVENT HANDLERS */

  handleClick (event) {
    const tgt = event.currentTarget
    this.setColumnHeaderSort(tgt.getAttribute('data-column-index'))
  }
}
```
